﻿/********************************************************************************************
 * InterIMAP
 * Copyright (C) 2008-2009 Jason Miesionczek
 * Original Author: Rohit Joshi
 * Based on this article on codeproject.com:
 * IMAP Client library using C#
 * http://www.codeproject.com/KB/IP/imaplibrary.aspx?msg=2498332
 * Posted: August 16th 2004
 * 
 * ZipStorer code written by Jaime Olivares
 * http://www.codeproject.com/KB/recipes/ZipStorer.aspx
 * 
 * InterIMAP is free software; you can redistribute it and/or modify it under the terms
 * of the GNU Lesser General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 * 
 * InterIMAP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with
 * InterIMAP. If not, see http://www.gnu.org/licenses/.
 * 
 * *****************************************************************************************/

using System;
using System.IO;

namespace InterIMAP
{
    /// <summary>
    /// Class to facilitate the logging of messages from the system when in debug mode
    /// </summary>
    public class IMAPLogger
    {
        #region Logging Enums
        /// <summary>
        /// The two different sources a logging event can come from. Used for debug level filtering
        /// </summary>
        public enum LoggingSource
        {
            /// <summary>
            /// Log all events generated by the IMAP client
            /// </summary>
            IMAP,
            /// <summary>
            /// Log all events generated by the IMAP client wrapper
            /// </summary>
            InterIMAP,
            /// <summary>
            /// Log all events generated by a message worker
            /// </summary>
            MessageWorker
        }

        /// <summary>
        /// The types of messages that can be logged
        /// </summary>
        public enum LogType
        {
            /// <summary>
            /// An informational event
            /// </summary>
            Info,
            /// <summary>
            /// A warning event
            /// </summary>
            Warning,
            /// <summary>
            /// An error event
            /// </summary>
            Error,
            /// <summary>
            /// An unlabeled event
            /// </summary>
            General
        }
        #endregion

        #region Private Fields
        private IMAPConfig.DebugDetailLevel _debugLevel;
        private IMAPConfig _config;
        private bool _paused;
        private readonly int _workerID;
        #endregion

        #region Public Delegate
        /// <summary>
        /// 
        /// </summary>
        /// <param name="logMsg"></param>
        public delegate void ExternalLogger(string logMsg);
        #endregion

        #region Public Events
        public event ExternalLogger EventLogged;
        #endregion

        #region Public Properties
        /// <summary>
        /// Temporarily stop all logging on the instance
        /// </summary>
        public bool Paused
        {
            get { return _paused; }
            set { _paused = value; }
        }
        /// <summary>
        /// Gets or Sets the amount of information is logged
        /// </summary>
        public IMAPConfig.DebugDetailLevel DetailLevel
        {
            get { return _debugLevel; }
            set { _debugLevel = value; }
        }

        /// <summary>
        /// The IMAPConfig object current associated with this logger
        /// </summary>
        public IMAPConfig Config
        {
            get { return _config; }
            set { _config = value; }
        }
        #endregion

        #region CTOR
        /// <summary>
        /// Default constructor. Requires to be initialized with an IMAPConfig instance
        /// </summary>
        /// <param name="config"></param>
        /// <param name="extraParams">Used to pass in the ID of the current message worker</param>
        public IMAPLogger(IMAPConfig config, params object[] extraParams)
        {
            _config = config;
            _debugLevel = config.DebugDetail;
            _workerID = -1;

            if (extraParams.Length>0)            
                _workerID = Convert.ToInt32(extraParams[0]);
            
            
        }
        #endregion

        #region Logging Methods
        /// <summary>
        /// Logs information to the console and optionally a log file
        /// </summary>
        /// <param name="source"></param>
        /// <param name="type"></param>
        /// <param name="msg"></param>        
        public virtual string Log(LoggingSource source, LogType type, string msg)
        {
            if (!_config.DebugMode || _paused)
                return String.Empty;
            
            string output = String.Empty;
            
            switch (_debugLevel)
            {
                case IMAPConfig.DebugDetailLevel.All:
                    {
                        output = GenerateMessage(type, msg);
                        break;
                    }
                case IMAPConfig.DebugDetailLevel.ErrorsOnly:
                    {
                        if (type == LogType.Error)
                            output = GenerateMessage(type, msg);
                        break;
                    }
                case IMAPConfig.DebugDetailLevel.InterIMAPOnly:
                    {
                        if (source == LoggingSource.InterIMAP || source == LoggingSource.MessageWorker)
                            output = GenerateMessage(type, msg);
                        break;
                    }
            }

            if (output != String.Empty)
            {
                if (_workerID > -1)
                    output = String.Format("Worker {0} - {1}", _workerID, output);
                Console.WriteLine(output);

                if (_config.LogFile != String.Empty)
                {
                    string logFile = _config.LogFile;
                    
                    if (_workerID > -1)
                    {
                        string file = Path.GetFileNameWithoutExtension(_config.LogFile);
                        string path = _config.LogFile.Replace(file, "{0}");
                        file += String.Format("_{0}", _workerID);
                        logFile = String.Format(path, file);
                    }
                    
                    StreamWriter strWriter = new StreamWriter(logFile, true);
                    strWriter.WriteLine("{0} - {1}", DateTime.Now, msg);
                    strWriter.Flush();
                    strWriter.Close();
                }

                if (EventLogged != null)
                {
                    EventLogged(output);
                }
            }

            return output;
        }

        private string GenerateMessage(LogType type, string msg)
        {
            switch (type)
            {
                case LogType.Error:
                    {
                        return String.Format("{0} - ERROR: {1}", DateTime.Now, msg);                        
                    }
                case LogType.General:
                    {
                        return String.Format("{0} - {1}", DateTime.Now, msg);                        
                    }
                case LogType.Info:
                    {
                        return String.Format("{0} - INFO: {1}", DateTime.Now, msg);                        
                    }
                case LogType.Warning:
                    {
                        return String.Format("{0} - WARNING: {1}", DateTime.Now, msg);                        
                    }
            }

            return String.Format("{0} - {1}", DateTime.Now, msg);
        }
        #endregion
    }
}
